home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / news / misc / enh-du / patch1-beta1 < prev    next >
Encoding:
Text File  |  1993-08-29  |  49.7 KB  |  1,617 lines

  1. This is a test version of patch 1 to enh-du2.
  2.  
  3. If you have any comments or problems, please contact Chip Rosenthal
  4. <chip@chinacat.unicom.com>.
  5.  
  6. From the Update-Notes file:
  7.  
  8. Patch:        1
  9. Version:    from 2.0 to 2.1
  10. Severity:    critical for SPARC users, moderate for others
  11.  
  12. Highlights:    Document critical bug on multi-processor SPARC systems.
  13.         Added option to dereference symlinks.  "dusort" now
  14.         handles files with embedded spaces.  Several portability
  15.         improvements.
  16.  
  17. Installation:    Apply this patch to the distributed enh-du2 v2.0
  18.         sources.  A new file called "config-dist" will be
  19.         created by this patch.  Recreate your "config.h" from
  20.         this file.  You should be able to use the same exact
  21.         configuration settings as you did with v2.0.  Although
  22.         a new USE_GETCWD_xxxx definition has been added, you
  23.         shouldn't have to change it from the distributed
  24.         setting.  It was added to support folks who could not
  25.         use v2.0.
  26.  
  27.  
  28. Index: patchlevel.h
  29. *** PL0/patchlevel.h    Tue Aug 24 18:00:15 1993
  30. --- patchlevel.h    Sun Aug 29 23:43:52 1993
  31. ***************
  32. *** 1,3 ****
  33. ! /* @(#) patchlevel.h 1.13 93/08/18 00:09:11 */
  34. ! #define VERSION "2.0"
  35. --- 1,2 ----
  36. ! /* @(#) patchlevel.h 1.15 93/08/29 23:43:45 */
  37. ! #define VERSION "2.0+beta1"
  38. Index: Update-Notes
  39. *** PL0/Update-Notes    Wed Aug 25 03:57:45 1993
  40. --- Update-Notes    Sun Aug 29 23:43:54 1993
  41. ***************
  42. *** 0 ****
  43. --- 1,65 ----
  44. + # @(#) Update-Notes 1.2 93/08/29 23:43:47
  45. + ------------------------------------------------------------------------------
  46. + Patch:        1
  47. + Version:    from 2.0 to 2.1
  48. + Severity:    critical for SPARC users, moderate for others
  49. + Highlights:    Document critical bug on multi-processor SPARC systems.
  50. +         Added option to dereference symlinks.  "dusort" now
  51. +         handles files with embedded spaces.  Several portability
  52. +         improvements.
  53. + Installation:    Apply this patch to the distributed enh-du2 v2.0
  54. +         sources.  A new file called "config-dist" will be
  55. +         created by this patch.  Recreate your "config.h" from
  56. +         this file.  You should be able to use the same exact
  57. +         configuration settings as you did with v2.0.  Although
  58. +         a new USE_GETCWD_xxxx definition has been added, you
  59. +         shouldn't have to change it from the distributed
  60. +         setting.  It was added to support folks who could not
  61. +         use v2.0.
  62. + Modified README with notes on *major* problem with multi-processor
  63. + SPARC.  This patch does NOT fix the problem, it just documents it.
  64. + Based upon reports from Bob Wakehouse <bob@tv.tv.tek.com>, Keith
  65. + Thompson <kst@flash.alsys.com>, and Szymon Sokol <szymon@uci.agh.edu.pl>.
  66. + Added "-S" option to dereference symlinks.
  67. + Renamed "config.h" to "config-dist" to avoid stomping on user's changes.
  68. + Ported to Ultrix based upon report from John Stoffel <john@wpi.edu>.
  69. + Ported to NeXT based upon report from Vince DeMarco <vince@whatnxt.cuc.ab.ca>.
  70. + Added USE_GETCWD_xxxx definitions for systems that don't have getcwd().
  71. + Fix type of Curr_time from long to time_t, as reported by John Stoffel
  72. + <john@wpi.edu>.
  73. + Removed obsolete "-d" option as threatened.
  74. + Display pathconf() failure diagnostic when compiled with DEBUG.
  75. + Modified "dusort" to make field delimiter the tab character instead
  76. + of any whitespace characters.  This allows filenames with embedded
  77. + spaces.  Based upon bug report from Kevin Ruland <kevin@rodin.wustl.edu>.
  78. + Added "-f" option to "dusort" to allow specification of field seperator.
  79. + Updated list of tested systems in README based upon reports from
  80. + Shabtai Lerner <slerner@eingedi.newton.ma.us>, Juha Laiho
  81. + <jlaiho@ichaos.nullnet.fi>, Fred Smith <fcshome!fredex>,
  82. + Matthew Costello <mattc@ncr-sd.sandiego.ncr.com>, and
  83. + Hans de Graaff <j.j.degraaff@duticai.twi.tudelft.nl>.
  84. + Fixed some typos in the README file.
  85. + Introduced (this) Update-Notes file with information on patch changes.
  86. + ------------------------------------------------------------------------------
  87. + [end of update information]
  88. Index: Makefile
  89. *** PL0/Makefile    Tue Aug 24 18:00:13 1993
  90. --- Makefile    Wed Aug 25 03:56:59 1993
  91. ***************
  92. *** 1,4 ****
  93. ! # @(#) Makefile 1.20 93/08/18 00:08:53
  94.   
  95.   ##############################################################################
  96.   #
  97. --- 1,4 ----
  98. ! # @(#) Makefile 1.22 93/08/25 03:56:46
  99.   
  100.   ##############################################################################
  101.   #
  102. ***************
  103. *** 83,90 ****
  104.   LINTFLAGS = $(CDEFS) -DNO_PROTOTYPE -DPTRTYPE=char
  105.   
  106.   FILES = README du.c duentry.c fsinfo.c dusort.c \
  107. !     patchlevel.h config.h du.h stdlib.h \
  108. !     Makefile ngsizes du.1 dusort.1 ngsizes.1
  109.   
  110.   all : du dusort ngsizes du.1 dusort.1 ngsizes.1
  111.   
  112. --- 83,90 ----
  113.   LINTFLAGS = $(CDEFS) -DNO_PROTOTYPE -DPTRTYPE=char
  114.   
  115.   FILES = README du.c duentry.c fsinfo.c dusort.c \
  116. !     patchlevel.h config-dist du.h stdlib.h \
  117. !     Makefile ngsizes du.1 dusort.1 ngsizes.1 Update-Notes
  118.   
  119.   all : du dusort ngsizes du.1 dusort.1 ngsizes.1
  120.   
  121. Index: README
  122. *** PL0/README    Tue Aug 24 18:00:09 1993
  123. --- README    Sun Aug 29 23:43:50 1993
  124. ***************
  125. *** 1,4 ****
  126. ! @(#) README 1.15 93/08/18 00:08:57
  127.   
  128.   "enh-du2" is a highly-portable, high-performance, POSIX-conformant
  129.   reimplementation of the "du" command.  It also adds some helpful
  130. --- 1,4 ----
  131. ! @(#) README 1.21 93/08/29 23:43:40
  132.   
  133.   "enh-du2" is a highly-portable, high-performance, POSIX-conformant
  134.   reimplementation of the "du" command.  It also adds some helpful
  135. ***************
  136. *** 13,31 ****
  137.   disk space used by the usenet news system.  It puts some of the
  138.   "enh-du2" features to good use.
  139.   
  140.   
  141.   === Contents =================================================================
  142.   
  143.       - Overview
  144.       - Installation
  145.       - Credits
  146.   
  147.   
  148.   === Overview =================================================================
  149.   
  150. ! Word to the impatient:  Edit "Makefile" and "config.h", then run "make".
  151.   
  152. ! This version supercedes the "enh-du" published in comp.sources.misc
  153.   volume 14.  The update is not intended to provide an explosion of
  154.   chrome and bloat (aka "gratuitous features").  This release mainly
  155.   improves portability, especially in heterogeneous networked environments.
  156. --- 13,41 ----
  157.   disk space used by the usenet news system.  It puts some of the
  158.   "enh-du2" features to good use.
  159.   
  160. +     *** IMPORTANT NOTE *******************************************
  161. +     *                                                            *
  162. +     * If you are running a multi-processor SPARC system do NOT   *
  163. +     * attempt to install this package until you fully read these *
  164. +     * notes.  Failure to do so could _crash_ your machine!       *
  165. +     *                                                            *
  166. +     **************************************************************
  167.   
  168.   === Contents =================================================================
  169.   
  170.       - Overview
  171.       - Installation
  172. +     - Urgent Note to SPARC Users
  173.       - Credits
  174.   
  175.   
  176.   === Overview =================================================================
  177.   
  178. ! Word to the impatient:  Copy "config-dist" to "config.h", configure it and
  179. ! and the "Makefile", then run "make".
  180.   
  181. ! This version supersedes the "enh-du" published in comp.sources.misc
  182.   volume 14.  The update is not intended to provide an explosion of
  183.   chrome and bloat (aka "gratuitous features").  This release mainly
  184.   improves portability, especially in heterogeneous networked environments.
  185. ***************
  186. *** 58,64 ****
  187.   been added to display a file count in addition to the disk usage.
  188.   
  189.   To give you a feel for what this program can do, here is the output
  190. ! of "du -h".  Portions of this message are site dependant, and so your
  191.   mileage may vary.
  192.   
  193.   du - version 2.0
  194. --- 68,74 ----
  195.   been added to display a file count in addition to the disk usage.
  196.   
  197.   To give you a feel for what this program can do, here is the output
  198. ! of "du -h".  Portions of this message are site dependent, and so your
  199.   mileage may vary.
  200.   
  201.   du - version 2.0
  202. ***************
  203. *** 91,96 ****
  204. --- 101,108 ----
  205.   are using something else, you've got a bit of work to do.  Here are the
  206.   steps to bring up the package:
  207.   
  208. +   - Copy "config-dist" to "config.h".
  209.     - Customize the "config.h" file for your system.
  210.   
  211.     - Customize the definitions at the top of the "Makefile".
  212. ***************
  213. *** 105,121 ****
  214.   
  215.       HP/9000 series 400    HP-UX 8.02
  216.       HP/9000 series 800    HP-UX 8.02
  217. !     IBM RS/6000        AIX3.1
  218.       NCR Tower        SysVr3.1 (NCR release 03.00.00)
  219. !     Sun SPARC        SunOS 4.1.2, Solaris 2.1
  220.       AT&T 3B1        SysVr3.2 (ver 3.51m)
  221.       AT&T 3B2        SysVr3.1
  222. !     386            AT&T SysV 3.2.2.3
  223. !     386            ISC SysVr3.2 versions 2.0.2, 2.2, 3.0.1
  224. !     386            MicroPort SysV 3.0U3.0e
  225. !     386            SCO Xenix 2.3.X
  226. !     386            SCO Unix 3.2v2, 3.2v4
  227. !     386            BSDI versions 0.9.2, 1.0
  228.   
  229.   If you get stuck configuring "enh-du", some possibly helpful information
  230.   follows.  I'll show you the settings I used when testing the package on
  231. --- 117,142 ----
  232.   
  233.       HP/9000 series 400    HP-UX 8.02
  234.       HP/9000 series 800    HP-UX 8.02
  235. !     IBM PS/2        AIX 1.3
  236. !     IBM RS/6000        AIX 3.1
  237.       NCR Tower        SysVr3.1 (NCR release 03.00.00)
  238. !     Sun SPARC        SunOS 4.1.2, 4.1.3 [see next section!!!]
  239. !     Sun SPARC        Solaris 2.1, 2.2
  240. !     DEC MIPS        Ultrix 4.3a
  241.       AT&T 3B1        SysVr3.2 (ver 3.51m)
  242.       AT&T 3B2        SysVr3.1
  243. !     Sequent S81        Dynix 3.0.17
  244. !     NeXT            NeXTSTEP 3.1
  245. !     NCR 3000 series        NCR releases 1.01.00.14, 02.00.02.02
  246. !     x86            AT&T SysV 3.2.2.3
  247. !     x86            ISC SysVr3.2 versions 2.0.2, 2.2, 3.0.1
  248. !     x86            MicroPort SysV 3.0U3.0e
  249. !     x86            SCO Xenix 2.3.X
  250. !     x86            SCO Unix 3.2v2, 3.2v4
  251. !     x86            BSDI versions 0.9.2, 1.0
  252. !     x86            Linux 0.99pl12 (gcc 2.4.5/libc 4.4.1)
  253. !     x86            Coherent 4.0.1
  254.   
  255.   If you get stuck configuring "enh-du", some possibly helpful information
  256.   follows.  I'll show you the settings I used when testing the package on
  257. ***************
  258. *** 138,143 ****
  259. --- 159,165 ----
  260.   USE_DIR_xxxx    DIRENT    -    -    -    -    -    -    -
  261.   USE_MOUNT_xxxx    MNTTAB    -    -    -    R4MNTTAB MNTENT    FSTAB    -
  262.   USE_STATFS_xxxx    SYSV    -    -    -    -    SUN    BSD    -
  263. + USE_GETCWD_xxxx    GETCWD    -    -    -    -    -    -    -
  264.   USE_SYMLINKS    disab    enab    -    -    enab    enab    enab    -
  265.   USE_STBLOCKS    disab    -    -    -    enab    enab    enab    -
  266.   BROKE_STBLOCKS    disab    -    -    -    -    -    -    -
  267. ***************
  268. *** 158,163 ****
  269. --- 180,220 ----
  270.   SunOS 4.1.2            (empty)        (empty)
  271.   BSDI 1.0            (empty)        (empty)
  272.   AT&T 3B2 and NCR Tower        -I.        -lmalloc
  273. + === Urgent Note to SPARC Users ===============================================
  274. + If you are running a multi-processor SPARC system do NOT attempt to
  275. + install this package until you fully read this section.  Failure to
  276. + do so could _crash_ your machine!
  277. + I have three independant reports from people who tried to run enh-du2
  278. + on their MP SPARC systems and the machine paniced.  Two of these people
  279. + were using SunOS 4.1.2 and the third was using SunOS 4.1.3.  I have
  280. + another report that said enh-du2 worked perfectly fine on a 630MP
  281. + running SunOS 4.1.3 with the jumbo patch 100726-09.  The person who
  282. + encountered the panic under 4.1.3 confirmed to me that this patch was
  283. + _not_ installed on his system.
  284. + Therefore, based upon these reports, I strongly advise anybody running
  285. + SunOS on an MP SPARC machine without patch 100726-009 to avoid this
  286. + package.  Furthermore, it appears that the aforementioned patch resolves
  287. + the system problem that enh-du2 trips over.
  288. + I have a gazillion uneventful reports from users of uniprocessor SPARC
  289. + systems (as well as first hand experience).  The problems appear to
  290. + be confined solely to MP SPARC systems.
  291. + All users should be assured that enh-du2 does NOT require any special
  292. + privileges.  It need not (and should not) be run setuid.  It does not
  293. + do any bizarre system or device operations.  It runs as a plain old,
  294. + normal user process.  Nothing it does should be capable of jeapordizing
  295. + a properly functioning system.  While it is almost certain there are
  296. + bugs lurking somewhere in this program (*sigh* aren't there always),
  297. + there is no way this program should be able to damage a machine.  The
  298. + fact that enh-du2 can cause certain machines to panic almost surely
  299. + indicates some sort of severe bug in the system hardware or operating
  300. + system.
  301.   
  302.   
  303.   === Credits ==================================================================
  304. Index: config-dist
  305. *** PL0/config-dist    Sat Aug 28 13:09:08 1993
  306. --- config-dist    Sun Aug 29 20:49:38 1993
  307. ***************
  308. *** 0 ****
  309. --- 1,198 ----
  310. + /* @(#) config-dist 1.17 93/08/29 20:49:32 
  311. +  *
  312. +  * "du" enhanced disk usage summary - version 2.
  313. +  *
  314. +  * Copyright 1990-1993, Unicom Systems Development.  All rights reserved.
  315. +  * See accompanying README file for terms of distribution and use.
  316. +  *
  317. +  * Edit at tabstops=8.
  318. +  *
  319. +  * This file must be configured for the target system.  Warning -- a lot
  320. +  * of this stuff is pretty obscure and esoteric.  That's unavoidable.
  321. +  * After all, we are dealing with some very low-level system facilities.
  322. +  * Moreover, some vendors take it upon themself to "value add" their Unix
  323. +  * to death, which just makes this task more difficult.
  324. +  *
  325. +  * With patience (and a good file pager) you will persevere!  I've tried
  326. +  * to provide hints and assistance wherever possible.  Nonetheless, chances
  327. +  * are very good that you will need to trawl through your /usr/include
  328. +  * directory to determine which selections are correct.
  329. +  *
  330. +  * If you get stuck, consult the README.  You'll find some hints for a
  331. +  * handful of systems that I have personally used.  If you have any
  332. +  * suggestions on how to make this task easier, let me know.
  333. +  */
  334. + /*
  335. +  * Select one of the following.  It says how to read directories.
  336. +  */
  337. + #define USE_DIR_DIRENT        /* use <dirent.h>, struct dirent       common */
  338. + /*#define USE_DIR_SYSDIR    /* use <sys/dir.h>, struct direct     old BSD */
  339. + /*#define USE_DIR_SYSNDIR    /* use <sys/ndir.h>, struct direct  old XENIX */
  340. + /*
  341. +  * Select one of the following.  It says how to look for mounted filesystems.
  342. +  */
  343. + #define USE_MOUNT_MNTTAB    /* use <mnttab.h>, use /etc/mnttab       SysV */
  344. + /*#define USE_MOUNT_R4MNTTAB    /* use <sys/mnttab.h>, /etc/mnttab     SysVr4 */
  345. + /*#define USE_MOUNT_MNTENT    /* use <mntent.h>, use /etc/mtab   SunOS,HPUX */
  346. + /*#define USE_MOUNT_FSTAB    /* use <fstab.h>, use /etc/fstab          BSD */
  347. + /*#define USE_MOUNT_MNTCTL    /* use <sys/mntctl.h>, use mntctl()       AIX */
  348. + /*
  349. +  * Select one of the following.  It says where your "struct statfs" is
  350. +  * defined -- or that your system doesn't support the "statfs()" call.
  351. +  */
  352. + #define USE_STATFS_SYSV        /* include <sys/statfs.h>                     */
  353. + /*#define USE_STATFS_BSD    /* include <sys/mount.h>              */
  354. + /*#define USE_STATFS_SUN    /* include <sys/vfs.h>, SysV-style stafs()    */
  355. + /*#define USE_STATFS_HPUX    /* include <sys/vfs.h>, BSD-style statfs()    */
  356. + /*#define USE_STATFS_ULTRIX    /* Ultrix-style statfs()              */
  357. + /*#define USE_STATFS_NONE    /* statfs() call not available, e.g. S5R2     */
  358. + /*
  359. +  * Selet one of the following.  It says what procedure is available to
  360. +  * get the current working directory.
  361. +  */
  362. + #define USE_GETCWD_GETCWD    /* use getcwd()                   common */
  363. + /*#define USE_GETCWD_GETCD    /* use getwd()            old BSD, NeXT */
  364. + /*#define USE_GETCWD_NONE    /* must run "pwd" command     ancient systems */
  365. + /*
  366. +  * Enable USE_SYMLINKS if you have symbolic links, else comment it out.
  367. +  *
  368. +  * It is important you enable this if appropriate.  It prevents "du" from
  369. +  * following symlinks that point to directories, and thus reporting bogus
  370. +  * results or ending up in strange twisted loops.
  371. +  */
  372. + /*#define USE_SYMLINKS         /* enable for SysVr4, Sun, etc. */
  373. + /*
  374. +  * Enable USE_STBLOCKS if the "stat" structure in your <sys/stat.h> file
  375. +  * has an "st_blocks" member, else comment it out.
  376. +  *
  377. +  * It is important to enable this if appropriate for two reasons.  First,
  378. +  * performance of "du" is *significantly* improved if "st_blocks"
  379. +  * information can be used.  Second, it will avoid reporting errors on
  380. +  * so-called "sparse" files.
  381. +  */
  382. + /*#define USE_STBLOCKS        /* enable for SysVr4, Sun, etc. */
  383. + /*
  384. +  * Leave BROKE_STBLOCKS undefined unless you really need it.
  385. +  *
  386. +  * If you didn't define USE_STBLOCKS above then don't even bother
  387. +  * reading this -- just leave BROKE_STBLOCKS undefined.
  388. +  *
  389. +  * This definition is provided as a workaround for certain vendors who
  390. +  * are a little confused about how Unix is supposed to work.  The
  391. +  * "st_blocks" information returned by stat(2) is supposed to be in
  392. +  * 512-byte blocks.  Some vendors botch this.  AIX, for example, properly
  393. +  * reports local filesystems in 512-byte blocks, but across the network
  394. +  * reports in 1024-byte blocks.  HPUX does the exact opposite.
  395. +  *
  396. +  * If you define BROKE_STBLOCKS, then "du" will try to calculate how
  397. +  * "st_blocks" should be interpreted rather than assuming 512-byte blocks.
  398. +  * This calculation, unfortunately, will fail for filesystems that use
  399. +  * fragments and the "f_bsize" value reported by statfs(2) is the block
  400. +  * size instead of the fragment size (e.g. Solaris, BSDI).
  401. +  *
  402. +  * So, enable BROKE_STBLOCKS only if all the following is true:
  403. +  *
  404. +  *    - You have defined USE_STBLOCKS.  If you haven't, BROKE_STBLOCKS
  405. +  *      is ignored anyway.
  406. +  *
  407. +  *    - "du" is reporting wrong values, usually either twice or half
  408. +  *      the correct size.
  409. +  *
  410. +  *    - Either you do not have a fast filesystem with fragments or
  411. +  *      "f_bsize" indicates the size of the fragment.
  412. +  *
  413. +  * (Please send a note to the author if you wish you could use
  414. +  * BROKE_STBLOCKS but can't because your system uses fragments.)
  415. +  */
  416. + /*#define BROKE_STBLOCKS    /* enable for HPUX, networked AIX */
  417. + /*
  418. +  * If your system has the ANSI <stdarg.h> facility then enable USE_STDARG.
  419. +  * If your system only has the older <varargs.h> then disable it.
  420. +  */
  421. + #define USE_STDARG        /* enable on ANSI-compliant systems */
  422. + /*
  423. +  * Enable USE_UNISTD if your system has a <unistd.h> file.
  424. +  * If you don't have this header file then disable it.
  425. +  */
  426. + #define USE_UNISTD        /* enable on ANSI-compliant systems */
  427. + /*
  428. +  * Enable USE_PATHCONF if your system has the POSIX pathconf() facility,
  429. +  * else comment it out.
  430. +  *
  431. +  * ===>    For some reason, this is the definition people seem to flub up
  432. +  *    most frequently.  If your system is an older, pre-POSIX system
  433. +  *    that lacks pathconf() then do NOT enable this.  If you ain't
  434. +  *    got it, I can't use it!
  435. +  *
  436. +  * If you enable USE_PATHCONF you *must* also have enabled USE_UNISTD.
  437. +  * If you disable USE_PATHCONF then we will make a (usually reasonable)
  438. +  * guess at how much space to reserve to hold pathnames.
  439. +  */
  440. + #define USE_PATHCONF        /* enable on POSIX-compliant systems */
  441. + /*
  442. +  * PTRTYPE indicates what your compiler uses as a generic pointer type.
  443. +  * Most modern compilers will accept "void".  Crufty compilers use "char".
  444. +  */
  445. + #ifndef PTRTYPE
  446. + #define PTRTYPE void        /* use (void *) as a generic pointer    */
  447. + /*#define PTRTYPE char        /* use (char *) as a generic pointer    */
  448. + #endif
  449. + /*
  450. +  * ### YOU ARE NOW FINISHED WITH THE ESSENTIAL CONFIGURATIONS ###
  451. +  * 
  452. +  * Congratulations!  You made it.  You are now ready to roll.
  453. +  *
  454. +  * You might, however, want to glance through the following definitions.
  455. +  * These allow you to tailor "du" behavior according to your site-specific
  456. +  * preferences.
  457. +  */
  458. + /*
  459. +  * REPORT_BLOCKSIZE specifies default block size to use for reporting
  460. +  * disk usage, usually either "512" or "1024".  Most versions of "du"
  461. +  * (including POSIX conformant versions) use 512.  Others, such as SunOS,
  462. +  * use 1024.  Pick whatever you prefer.  This choice does not effect the
  463. +  * usage calculations or accuracy, only how the results are displayed,
  464. +  * and there are command line switches that will override the default
  465. +  * selected here.
  466. +  */
  467. + #define REPORT_BLKSIZE        512    /* report in 512-byte blocks    */
  468. + /*#define REPORT_BLKSIZE    1024    /* report in 1024-byte blocks   */
  469. + /*
  470. +  * PRINT_ERRORS controls whether or not error messages (e.g. "permission
  471. +  * denied", etc.) are displayed.  When defined, these error messages are
  472. +  * displayed.  When disabled, the errors are silently ignored -- which
  473. +  * is traditional "du" behavior.  I think it makes more sense to print
  474. +  * the errors (i.e. enable PRINT_ERRORS).  If, however, you disable this
  475. +  * to obtain backward compatibility, you will get a "-r" command line
  476. +  * option that will turn error messages back on.
  477. +  */
  478. + #define PRINT_ERRORS        /* display errors by default if enabled */
  479. + /*
  480. +  * TIMEOUT is a release hatch for hung NFS servers.  If you define
  481. +  * this value, "du" will unceremoniously kill itself after this many
  482. +  * seconds of inactivity.
  483. +  */
  484. + /*#define TIMEOUT    300    /* timeout value in seconds        */
  485. + /*
  486. +  * MAX_BREAK is maximum number of columns which can be requested by the
  487. +  * "-c" option (breakdown usage by age).  Increasing this value will
  488. +  * increase the memory usage, but not by much.
  489. +  */
  490. + #define MAX_BREAK    64    /* max columns in breakdown by age    */
  491. Index: du.1
  492. *** PL0/du.1    Tue Aug 24 18:00:09 1993
  493. --- du.1    Sun Aug 29 20:39:52 1993
  494. ***************
  495. *** 1,4 ****
  496. ! .\" @(#) du.1 1.13 93/08/18 00:08:59
  497.   .TH DU 1
  498.   .SH NAME
  499.   du \- Summarizes disk usage.
  500. --- 1,4 ----
  501. ! .\" @(#) du.1 1.14 93/08/29 20:39:20
  502.   .TH DU 1
  503.   .SH NAME
  504.   du \- Summarizes disk usage.
  505. ***************
  506. *** 5,11 ****
  507.   .SH SYNTAX
  508.   .B du
  509.   [
  510. ! .B \-abCdfFhiklLstu
  511.   ] [
  512.   .B \-B
  513.   size ] [
  514. --- 5,11 ----
  515.   .SH SYNTAX
  516.   .B du
  517.   [
  518. ! .B \-abCdfFhiklLsStu
  519.   ] [
  520.   .B \-B
  521.   size ] [
  522. ***************
  523. *** 220,225 ****
  524. --- 220,237 ----
  525.   reports the disk usage for each directory it encounters.  This
  526.   option suppresses that information and instead reports just a
  527.   total usage for each of the items specified on the command line.
  528. + .IP "\-S" 10
  529. + This option is available only on systems that support symbolic links
  530. + (symlinks).  Normally,
  531. + .I du
  532. + accumulates the usage of the symlink itself and not the entry to which
  533. + it points.  When this option is specified,
  534. + .I du
  535. + will dereference symlinks and will accumulate the usage of the entry
  536. + to which they point.  Moreover, if a symlink is encountered that points
  537. + to a directory, then
  538. + .I du
  539. + will descend into that directory.
  540.   .IP "\-t" 10
  541.   A grand total of all items specified on the command line will be
  542.   accumulated and displayed.  For example, the command
  543. ***************
  544. *** 267,272 ****
  545. --- 279,305 ----
  546.   .BR \-a ,
  547.   all files will be displayed, but ones not owned by the specified
  548.   user will be shown as zero sized.
  549. + .P
  550. + The
  551. + .B \-S
  552. + option works in strange and mysterious ways; the following apply when
  553. + it is used.  This option introduces significant amounts of overhead
  554. + and degrades the performance severely.  You can create loops with
  555. + symlinks, and
  556. + .I du
  557. + will happily spin round and round until it bails out with an error.
  558. + If the
  559. + .I name
  560. + specified on the command line is not a full pathname, then
  561. + .I du
  562. + will convert it to one.  The full pathname and not the specified
  563. + .I name
  564. + will be displayed in the results.  Note that specifying no name is
  565. + equivalent to specifying ``.''.  The
  566. + .B \-L
  567. + option to average usage across links cannot be used.  The other options
  568. + that specify link handling should work.  The default behavior, to
  569. + count a file only once, applies even when symlinks are dereferenced.
  570.   .P
  571.   If two or more directory trees specified on the command line are not
  572.   disjoint, then the usage calculations will be corrupted by the presence
  573. Index: du.c
  574. *** PL0/du.c    Tue Aug 24 18:00:14 1993
  575. --- du.c    Sun Aug 29 20:49:36 1993
  576. ***************
  577. *** 1,5 ****
  578.   #ifndef lint
  579. ! static char SCCSID[] = "@(#) du.c 1.16 93/08/18 00:09:01";
  580.   #endif
  581.   static char Copyright[] = "@(#) Copyright 1990-1993, Unicom Systems Development, Inc.  All rights reserved.";
  582.   
  583. --- 1,5 ----
  584.   #ifndef lint
  585. ! static char SCCSID[] = "@(#) du.c 1.18 93/08/29 20:49:18";
  586.   #endif
  587.   static char Copyright[] = "@(#) Copyright 1990-1993, Unicom Systems Development, Inc.  All rights reserved.";
  588.   
  589. ***************
  590. *** 28,35 ****
  591.   #else
  592.   # include <varargs.h>
  593.   #endif
  594. - #include <sys/types.h>
  595. - #include <sys/stat.h>
  596.   #define INTERN
  597.   #include "du.h"
  598.   #include "patchlevel.h"
  599. --- 28,33 ----
  600. ***************
  601. *** 64,70 ****
  602.       /* 
  603.        * Crack command line options.
  604.        */
  605. !     while ((i = getopt(argc, argv, "abB:c:CDdfFhiklLrstuU:")) != EOF) {
  606.           switch (i) {
  607.               case 'a':    Handle_output = PR_EVERYTHING;        break;
  608.               case 'b':   Report_blksize = 1;                    break;
  609. --- 62,68 ----
  610.       /* 
  611.        * Crack command line options.
  612.        */
  613. !     while ((i = getopt(argc, argv, "abB:c:CDfFhiklLrsStuU:")) != EOF) {
  614.           switch (i) {
  615.               case 'a':    Handle_output = PR_EVERYTHING;        break;
  616.               case 'b':   Report_blksize = 1;                    break;
  617. ***************
  618. *** 71,79 ****
  619.               case 'B':   Report_blksize = atoi(optarg);        break;
  620.               case 'c':    set_breakdown(optarg);                break;
  621.               case 'C':    Do_file_counts = TRUE;                break;
  622. - #ifdef OBSOLETEOPT
  623. -             case 'd':    Do_descend_dirs = FALSE;            break;
  624. - #endif
  625.               case 'f':    Handle_filesys = FS_NEVER_CROSS;    break;
  626.               case 'F':    Handle_filesys = FS_LOCAL_ONLY;        break;
  627.               case 'h':    do_help();                            exit(0);
  628. --- 69,74 ----
  629. ***************
  630. *** 83,88 ****
  631. --- 78,86 ----
  632.               case 'L':    Handle_links = LK_COUNT_AVERAGE;    break;
  633.               case 'r':    Do_print_errors = TRUE;                break;
  634.               case 's':    Handle_output = PR_TOTALS_ONLY;        break;
  635. + #ifdef USE_SYMLINKS
  636. +             case 'S':    Follow_symlinks = TRUE;                break;
  637. + #endif
  638.               case 't':    Do_print_grand_total = TRUE;        break;
  639.               case 'u':    Handle_links = LK_COUNT_NONE;        break;
  640.               case 'U':    Selected_user = get_userid(optarg);    break;
  641. ***************
  642. *** 94,99 ****
  643. --- 92,107 ----
  644.           }
  645.       }
  646.   
  647. +     /*
  648. +      * Sanity checks.
  649. +      */
  650. + #ifdef USE_SYMLINKS
  651. +     if (Follow_symlinks && Handle_links == LK_COUNT_AVERAGE) {
  652. +         errmssg(ERR_ABORT, 0,
  653. +             "cannot average usage (-L) when dereferencing symlinks (-S)");
  654. +     }
  655. + #endif
  656.   #ifdef TIMEOUT
  657.       /*
  658.        * Install the handler to trap timeouts.
  659. ***************
  660. *** 143,151 ****
  661.       "                  (Use \"0\" to report in native filesystem blocks.)",
  662.       "    -c n,n,...  Breakdown by age, one col for each \"n\" days or older.",
  663.       "    -C          Display file counts as well as disk usage.",
  664. - #ifdef OBSOLETEOPT
  665. -     "    -d          Do not descend into directories.",
  666. - #endif
  667.       "    -f          Do not cross any filesystem mount points.",
  668.       "    -F          Do not cross remote filesystem mount points.",
  669.       "    -h          Display this help message.",
  670. --- 151,156 ----
  671. ***************
  672. *** 157,162 ****
  673. --- 162,170 ----
  674.       "    -r          Print (do not suppress) errors which occur during scan.",
  675.   #endif
  676.       "    -s          Only report a total for each argument on command line.",
  677. + #ifdef USE_SYMLINKS
  678. +     "    -S          Dereference and follow symlinks.",
  679. + #endif
  680.       "    -t          Report a grand total of all items.",
  681.       "    -u          Skip (do not count) multiply linked files entirely.",
  682.       "    -U user     Report only usage by given user (specify name or id num).",
  683. Index: du.h
  684. *** PL0/du.h    Tue Aug 24 18:00:14 1993
  685. --- du.h    Sun Aug 29 23:43:53 1993
  686. ***************
  687. *** 1,4 ****
  688. ! /* @(#) du.h 1.15 93/08/18 00:09:02 
  689.    *
  690.    * "du" enhanced disk usage summary - version 2.
  691.    *
  692. --- 1,4 ----
  693. ! /* @(#) du.h 1.20 93/08/29 23:43:15
  694.    *
  695.    * "du" enhanced disk usage summary - version 2.
  696.    *
  697. ***************
  698. *** 59,80 ****
  699.   
  700.   
  701.   /*
  702. !  * Structure to accumulate usage statistics.
  703.    *
  704. !  * The statistics are accumulated in a chronological breakdown, as
  705. !  * specified by "Num_break" and the "Breakdown[]" array.  "Num_break"
  706. !  * indicates the number of columns in the breakdown, and "Breakdown[]"
  707. !  * specifies the age for each of those columns.
  708. !  *
  709. !  * The "Num_break" value will range from 1 to MAX_BREAK.  The "blocks[n]"
  710. !  * value accumulates the disk usage of all filesystem entries "Breakdown[n]"
  711. !  * days or older.  The "files[n]" value counts the number of filesystem
  712. !  * entries that contributed to that total.
  713. !  *
  714. !  * By default, "Num_break" will be 1 and "Breakdown[0]" will be 0.  That
  715. !  * says accumulate a single set of statistics for all filesystem entries
  716. !  * zero days old or older (i.e. everything).
  717. !  *
  718.    */
  719.   struct dusage {
  720.       long blocks[MAX_BREAK];    /* accumulated disk usage                    */
  721. --- 59,84 ----
  722.   
  723.   
  724.   /*
  725. !  * (struct dusage) - structure to accumulate usage statistics.
  726.    *
  727. !  * The disk usage statistics are maintained in a chronological breakdown
  728. !  * and stored in a (struct dusage).  The breakdown conditions are specified
  729. !  * by the "Breakdown[]" array and the "Num_break" value.  The "Num_break"
  730. !  * value ranges from 1 to MAX_BREAK and specifies how many elements of
  731. !  * the "Breakdown[]" array are used.
  732. !  *
  733. !  * Each element of the "Breakdown[]" array is a number of days.  The
  734. !  * arrays in the (struct dusage) contain the usage information corresponding
  735. !  * to this breakdown.  That is, the "blocks[N]" value accumulates the
  736. !  * number of disk blocks used by filesystem entries that are "Breakdown[N]"
  737. !  * days or older.  The "files[N]" value accumulates the number of filesystem
  738. !  * entries encountered that are "Breakdown[N]" days or older.
  739. !  *
  740. !  * The default condition is "Num_break" equals one, and "Breakdown[0]"
  741. !  * equals zero.  That is, there is just a single entry in the chronological
  742. !  * breakdown, and it corresponds to all filesystem entries zero days or
  743. !  * older (which means everything).  A different breakdown can be set with
  744. !  * the "-c" command line option.
  745.    */
  746.   struct dusage {
  747.       long blocks[MAX_BREAK];    /* accumulated disk usage                    */
  748. ***************
  749. *** 135,152 ****
  750.    */
  751.   EXTERN BOOL Do_file_counts INIT(FALSE);
  752.   
  753. ! #ifdef OBSOLETEOPT
  754.   /*
  755. !  * If true, descend into directories and accumulate usage (subject to
  756. !  * filesystem handling at mount points).  If false, do not descend into
  757. !  * directories and simply report the usage of the directory filesystem
  758. !  * entry (i.e. sans contents) as its usage.
  759. !  *
  760. !  * This is a pretty useless option, but was present in the original
  761. !  * "enh-du".  Unless somebody tells me they really use it, it is
  762. !  * subject to removal in a future version.
  763.    */
  764. ! EXTERN BOOL Do_descend_dirs INIT(TRUE);
  765.   #endif
  766.   
  767.   /*
  768. --- 139,152 ----
  769.    */
  770.   EXTERN BOOL Do_file_counts INIT(FALSE);
  771.   
  772. ! #ifdef USE_SYMLINKS
  773.   /*
  774. !  * If true, dereference symlinks.  This means that the disk usage of the
  775. !  * entry to which the symlink points will be counted, instead of the usage
  776. !  * of the symlink itself.  Moreover, if the symlink points to a directory
  777. !  * then we will descend into it.
  778.    */
  779. ! EXTERN BOOL Follow_symlinks INIT(FALSE);
  780.   #endif
  781.   
  782.   /*
  783. ***************
  784. *** 186,192 ****
  785.   
  786.   /*
  787.    * Number of columns in the chronological breakdown.
  788. !  * Specifies number of elements in "Breakdown[]" that are actually used.
  789.    */
  790.   EXTERN int Num_break INIT(1);
  791.   
  792. --- 186,192 ----
  793.   
  794.   /*
  795.    * Number of columns in the chronological breakdown.
  796. !  * See comments in the (struct dusage) declaration for more info.
  797.    */
  798.   EXTERN int Num_break INIT(1);
  799.   
  800. ***************
  801. *** 193,199 ****
  802.   /*
  803.    * Current time, used for calculation of the chronological breakdown.
  804.    */
  805. ! EXTERN long Curr_time;
  806.   
  807.   
  808.   #if defined(__STDC__) && !defined(NO_PROTOTYPE)
  809. --- 193,199 ----
  810.   /*
  811.    * Current time, used for calculation of the chronological breakdown.
  812.    */
  813. ! EXTERN time_t Curr_time;
  814.   
  815.   
  816.   #if defined(__STDC__) && !defined(NO_PROTOTYPE)
  817. ***************
  818. *** 212,225 ****
  819.   void set_usage __ARGS((struct dusage *, time_t, long));
  820.   void add_usage __ARGS((struct dusage *, struct dusage *));
  821.   void print_usage __ARGS((char *, struct dusage *));
  822. - int max_path_len __ARGS((char *));
  823.   void du_entry __ARGS((char *, struct dusage *));
  824. ! int du_dir __ARGS((char *, struct stat    *, struct fsinfo *, struct dusage *));
  825.   void fs_initinfo __ARGS((void));
  826.   struct fsinfo *fs_getinfo __ARGS((struct stat *));
  827.   int fs_linkdone __ARGS((struct fsinfo *, struct stat *));
  828.   long fs_numblocks __ARGS((struct fsinfo *, struct stat *));
  829.   
  830.   extern int errno;
  831.   
  832. --- 212,225 ----
  833.   void set_usage __ARGS((struct dusage *, time_t, long));
  834.   void add_usage __ARGS((struct dusage *, struct dusage *));
  835.   void print_usage __ARGS((char *, struct dusage *));
  836.   void du_entry __ARGS((char *, struct dusage *));
  837. ! int du_dir __ARGS((char *, struct stat *, struct fsinfo *, struct dusage *));
  838. ! int max_path_len __ARGS((char *));
  839. ! char *get_curr_dir __ARGS((void));
  840.   void fs_initinfo __ARGS((void));
  841.   struct fsinfo *fs_getinfo __ARGS((struct stat *));
  842.   int fs_linkdone __ARGS((struct fsinfo *, struct stat *));
  843.   long fs_numblocks __ARGS((struct fsinfo *, struct stat *));
  844.   
  845.   extern int errno;
  846.   
  847. Index: duentry.c
  848. *** PL0/duentry.c    Tue Aug 24 18:00:10 1993
  849. --- duentry.c    Sun Aug 29 23:43:52 1993
  850. ***************
  851. *** 1,5 ****
  852.   #ifndef lint
  853. ! static char SCCSID[] = "@(#) duentry.c 1.18 93/08/18 00:09:03";
  854.   #endif
  855.   
  856.   /*
  857. --- 1,5 ----
  858.   #ifndef lint
  859. ! static char SCCSID[] = "@(#) duentry.c 1.23 93/08/29 23:43:19";
  860.   #endif
  861.   
  862.   /*
  863. ***************
  864. *** 34,76 ****
  865.   #    define dirent direct
  866.   #endif
  867.   
  868. - #ifndef USE_SYMLINKS
  869. - #    define lstat stat
  870. - #endif
  871.   /*
  872. !  * Determine maximum pathlength of an entry on the filesystem containing "file".
  873.    */
  874. ! int max_path_len(fname)
  875. ! register char *fname;
  876. ! {
  877. ! #ifdef USE_PATHCONF
  878. !     register int len;
  879. !     if ((len = pathconf(fname, _PC_PATH_MAX)) > 0)
  880. !         return len;
  881. ! #ifdef notdef
  882. !     errmssg(ERR_WARN, errno, "could not get max pathname for \"%s\"", fname);
  883. ! #endif
  884. ! #endif
  885.   
  886.   /*
  887. !  * If pathconf() is not available or fails, we need to take a stab.  If
  888. !  * the POSIX PATH_MAX parameter is available we will use that.  If not,
  889. !  * we will try to use the MAXNAMLEN that should be in whatever header
  890. !  * file USE_DIR_XXXX pulled in.  If all that fails, we'll just make a
  891. !  * guess of 1024.  Note that we do NOT want to use _POSIX_PATH_MAX.  That
  892. !  * specifies the minimum value that a conformant system must support.
  893.    */
  894. - #ifndef PATH_MAX
  895. - # ifdef MAXNAMLEN
  896. - #  define PATH_MAX MAXNAMLEN
  897. - # else
  898. - #  define PATH_MAX 1024
  899. - # endif
  900. - #endif
  901. -     return PATH_MAX;
  902. - }
  903.   
  904.   
  905.   /*
  906. --- 34,81 ----
  907.   #    define dirent direct
  908.   #endif
  909.   
  910.   /*
  911. !  * Pointer to the procedure we want to use to retrieve inode status.
  912. !  * Will point to either stat() or lstat(), depending upon how symlinks
  913. !  * are being handled.
  914.    */
  915. ! static int (*stat_proc) __ARGS((const char *, struct stat *));
  916.   
  917.   /*
  918. !  * Symlink handling is messy enough and craps up the logic enough that
  919. !  * it's worth discussing a little...
  920. !  *
  921. !  * This utility obtains the disk usage of a subdirectory by doing a chdir
  922. !  * into it, scanning it, and then doing a chdir back to the parent
  923. !  * directory when done.  Normally, that last part is just a simple
  924. !  * chdir("..").  When symlinks are being dereferenced (-S specified) that
  925. !  * may not work.
  926. !  *
  927. !  * Say "/foo/bar/baz" is a symlink to /blurfl/bonk.  To get the usage of
  928. !  * subdirectory "baz" we do a chdir("baz"), scan it, and then go back to
  929. !  * the parent.  A chdir(".."), unfortunately, will not put us in "/foo/bar",
  930. !  * but instead in "/blurfl".  We must, therefore, specify the full pathname
  931. !  * of the parent directory ("/foo/bar" in this example) when symlinks
  932. !  * are being dereferenced.  We should, however, do this _only_ when
  933. !  * symlinks are being dereferenced; it incurs a significant performance
  934. !  * penalty.
  935. !  *
  936. !  * Since we need to use full pathnames when symlinks are dereferenced,
  937. !  * this means that we cannot accept relative pathnames from the user.
  938. !  * If the user gives us a relative pathname we must expand it to a fully
  939. !  * rooted pathname.  Consider what happens, given the directory structure
  940. !  * in the above example, when the user types "cd /foo ; du .".  When we
  941. !  * get done scanning the "baz" directory we need to leave it by doing a
  942. !  * chdir("/foo/bar") and not chdir("./bar").
  943. !  *
  944. !  * There is one last twist.  By default, we try to count files only once.
  945. !  * To avoid a lot of unnecessary work, we normally do the checks only if
  946. !  * st_nlink is greater than one (i.e. the file has multiple hard links).
  947. !  * When dereferencing symlinks, however, we can visit a file multiple
  948. !  * times even if it does not have multiple hard links.  In this case we
  949. !  * need to perform those checks for _every_ file, and not just the ones
  950. !  * where st_nlink > 1.  (Oy! The overhead!)
  951.    */
  952.   
  953.   
  954.   /*
  955. ***************
  956. *** 86,92 ****
  957.   {
  958.       struct stat sbuf;
  959.       struct fsinfo *fsinfo;
  960. !     static char *curr_dir = NULL;
  961.   
  962.   #ifdef TIMEOUT
  963.       alarm(TIMEOUT);
  964. --- 91,97 ----
  965.   {
  966.       struct stat sbuf;
  967.       struct fsinfo *fsinfo;
  968. !     static char *start_dir = NULL;
  969.   
  970.   #ifdef TIMEOUT
  971.       alarm(TIMEOUT);
  972. ***************
  973. *** 93,101 ****
  974.   #endif
  975.   
  976.       /*
  977.        * Get the information on this entry.
  978.        */
  979. !     if (lstat(entry, &sbuf) != 0) {
  980.           errmssg(ERR_WARN, errno, "could not stat \"%s\"", entry);
  981.           return;
  982.       }
  983. --- 98,115 ----
  984.   #endif
  985.   
  986.       /*
  987. +      * Determine what procedure should be used to retrieve inode status.
  988. +      */
  989. + #ifdef USE_SYMLINKS
  990. +     stat_proc = (Follow_symlinks ? stat : lstat);
  991. + #else
  992. +     stat_proc = stat;
  993. + #endif
  994. +     /*
  995.        * Get the information on this entry.
  996.        */
  997. !     if ((*stat_proc)(entry, &sbuf) != 0) {
  998.           errmssg(ERR_WARN, errno, "could not stat \"%s\"", entry);
  999.           return;
  1000.       }
  1001. ***************
  1002. *** 117,147 ****
  1003.           return;
  1004.       }
  1005.   
  1006. - #ifdef OBSOLETEOPT
  1007. -     /*
  1008. -      * If we aren't supposed to descend into directories then just get
  1009. -      * it's size.
  1010. -      */
  1011. -     if (!Do_descend_dirs) {
  1012. -         set_usage(ent_usage, sbuf.st_mtime, fs_numblocks(fsinfo, &sbuf));
  1013. -         print_usage(entry, ent_usage);
  1014. -         return;
  1015. -     }
  1016. - #endif
  1017.       /*
  1018.        * We are about to descend down this directory entry.  We need to
  1019.        * know where we started out so that we can return when done.
  1020.        */
  1021. !     if (curr_dir == NULL) {
  1022. !         int len;
  1023. !         extern char *getcwd();
  1024. !         len = max_path_len(".") + 2; /* getcwd() wants two extra bytes */
  1025. !         curr_dir = (char *) xmalloc((unsigned)len);
  1026. !         if (errno = 0, getcwd(curr_dir, len) == NULL)
  1027. !             errmssg(ERR_ABORT, errno,
  1028. !                 "could not get current working directory");
  1029. !     }
  1030.   
  1031.       /*
  1032.        * We need to initiate a recursive search through "du_dir()".  Normally
  1033. --- 131,142 ----
  1034.           return;
  1035.       }
  1036.   
  1037.       /*
  1038.        * We are about to descend down this directory entry.  We need to
  1039.        * know where we started out so that we can return when done.
  1040.        */
  1041. !     if (start_dir == NULL)
  1042. !         start_dir = get_curr_dir();
  1043.   
  1044.       /*
  1045.        * We need to initiate a recursive search through "du_dir()".  Normally
  1046. ***************
  1047. *** 154,165 ****
  1048.           errmssg(ERR_WARN, errno, "could not chdir to \"%s\"", entry);
  1049.           return;
  1050.       }
  1051.       if (du_dir(entry, &sbuf, fsinfo, ent_usage) == 0) {
  1052.           if (Handle_output == PR_TOTALS_ONLY)
  1053.               print_usage(entry, ent_usage);
  1054.       }
  1055. !     if (chdir(curr_dir) != 0)
  1056. !         errmssg(ERR_ABORT, errno, "could not chdir back to \"%s\"", curr_dir);
  1057.   
  1058.   }
  1059.   
  1060. --- 149,169 ----
  1061.           errmssg(ERR_WARN, errno, "could not chdir to \"%s\"", entry);
  1062.           return;
  1063.       }
  1064. + #ifdef USE_SYMLINKS
  1065. +     /*
  1066. +      * If we are dereferencing symlinks then we need to have a fully rooted
  1067. +      * pathname.  Note that this messes up the name that will be printed
  1068. +      * in the output.  Also note that this is a memory leak.  So sue me.
  1069. +      */
  1070. +     if (Follow_symlinks && entry[0] != '/')
  1071. +         entry = get_curr_dir();
  1072. + #endif
  1073.       if (du_dir(entry, &sbuf, fsinfo, ent_usage) == 0) {
  1074.           if (Handle_output == PR_TOTALS_ONLY)
  1075.               print_usage(entry, ent_usage);
  1076.       }
  1077. !     if (chdir(start_dir) != 0)
  1078. !         errmssg(ERR_ABORT, errno, "could not chdir back to \"%s\"", start_dir);
  1079.   
  1080.   }
  1081.   
  1082. ***************
  1083. *** 245,251 ****
  1084.           /*
  1085.            * Get the information on this entry.
  1086.            */
  1087. !         if (lstat(dp->d_name, &ent_stat) != 0) {
  1088.               errmssg(ERR_WARN, errno,
  1089.                   "could not stat \"%s/%s\"", dir_name, dp->d_name);
  1090.               continue;
  1091. --- 249,255 ----
  1092.           /*
  1093.            * Get the information on this entry.
  1094.            */
  1095. !         if ((*stat_proc)(dp->d_name, &ent_stat) != 0) {
  1096.               errmssg(ERR_WARN, errno,
  1097.                   "could not stat \"%s/%s\"", dir_name, dp->d_name);
  1098.               continue;
  1099. ***************
  1100. *** 283,288 ****
  1101. --- 287,301 ----
  1102.                           "internal error - bad \"Handle_links\" value \"%d\"",
  1103.                           Handle_links);
  1104.                   }
  1105. + #ifdef USE_SYMLINKS
  1106. +             /*
  1107. +              * Make sure that files with a single link aren't duplicated
  1108. +              * due to dereferencing of symlinks.
  1109. +              */
  1110. +             } else if (Follow_symlinks && Handle_links == LK_COUNT_FIRST
  1111. +                     && fs_linkdone(dir_fsinfo, &ent_stat)) {
  1112. +                 continue;
  1113. + #endif
  1114.               }
  1115.   
  1116.               /*
  1117. ***************
  1118. *** 348,354 ****
  1119.                   if (Do_accum_subdirs)
  1120.                       add_usage(dir_usage, &ent_usage);
  1121.               }
  1122. !             if (chdir("..") != 0) {
  1123.                   errmssg(ERR_ABORT, errno,
  1124.                       "could not chdir back to \"%s\"", dir_name);
  1125.               }
  1126. --- 361,373 ----
  1127.                   if (Do_accum_subdirs)
  1128.                       add_usage(dir_usage, &ent_usage);
  1129.               }
  1130. !             if (
  1131. ! #ifdef USE_SYMLINKS
  1132. !                 chdir(Follow_symlinks ? dir_name : "..") != 0
  1133. ! #else
  1134. !                 chdir("..") != 0
  1135. ! #endif
  1136. !             ) {
  1137.                   errmssg(ERR_ABORT, errno,
  1138.                       "could not chdir back to \"%s\"", dir_name);
  1139.               }
  1140. ***************
  1141. *** 365,369 ****
  1142. --- 384,476 ----
  1143.           print_usage(dir_name, dir_usage);
  1144.       (void) free((PTRTYPE *)ent_pathname);
  1145.       return 0;
  1146. + }
  1147. + /*
  1148. +  * Determine maximum pathlength of an entry on the filesystem containing "file".
  1149. +  */
  1150. + int max_path_len(fname)
  1151. + register char *fname;
  1152. + {
  1153. + #ifdef USE_PATHCONF
  1154. +     register int len;
  1155. +     if ((len = pathconf(fname, _PC_PATH_MAX)) > 0)
  1156. +         return len;
  1157. + #ifdef DEBUG
  1158. +     /*
  1159. +      * I've seen some systems where pathconf() will fail, most notably
  1160. +      * on NFS filesystems.  So, the diagnostic is normally suppressed.
  1161. +      */
  1162. +     errmssg(ERR_WARN, errno, "pathconf() could not get path_max for \"%s\"", fname);
  1163. + #endif
  1164. + #endif
  1165. + /*
  1166. +  * If pathconf() is not available or fails, we need to take a stab.  If
  1167. +  * the POSIX PATH_MAX parameter is available we will use that.  If not,
  1168. +  * we will try to use the MAXNAMLEN that should be in whatever header
  1169. +  * file USE_DIR_XXXX pulled in.  If all that fails, we'll just make a
  1170. +  * guess of 1024.  Note that we do NOT want to use _POSIX_PATH_MAX.  That
  1171. +  * specifies the minimum value that a conformant system must support.
  1172. +  */
  1173. + #ifndef PATH_MAX
  1174. + # ifdef MAXNAMLEN
  1175. + #  define PATH_MAX MAXNAMLEN
  1176. + # else
  1177. + #  define PATH_MAX 1024
  1178. + # endif
  1179. + #endif
  1180. +     return PATH_MAX;
  1181. + }
  1182. + /*
  1183. +  * Get the current working directory.
  1184. +  */
  1185. + char *get_curr_dir()
  1186. + {
  1187. +     char *d;
  1188. +     int maxlen, ok;
  1189. +     maxlen = max_path_len(".");
  1190. +     d = xmalloc(maxlen+2);    /* getcwd() wants two extra bytes */
  1191. +     errno = 0;
  1192. + #ifdef USE_GETCWD_GETCWD
  1193. +     {
  1194. + #ifndef USE_UNISTD
  1195. +         extern char *getcwd();
  1196. + #endif
  1197. +         ok = (getcwd(d, maxlen) != NULL);
  1198. +     }
  1199. + #endif
  1200. + #ifdef USE_GETCWD_GETWD
  1201. +     {
  1202. +         extern char *getwd();
  1203. +         ok = (getwd(d) != NULL);
  1204. +     }
  1205. + #endif
  1206. + #ifdef USE_GETCWD_NONE
  1207. +     {
  1208. +         FILE *fp;
  1209. +         char *s;
  1210. +         ok = ((fp = popen("pwd", "r")) != NULL
  1211. +                 && fgets(d, maxlen, fp) != NULL && pclose(fp) == 0);
  1212. +         if (ok && (s = strchr(d, '\n')) != NULL)
  1213. +             *s = '\0';
  1214. +     }
  1215. + #endif
  1216. +     if (!ok)
  1217. +         errmssg(ERR_ABORT, errno, "could not get current working directory");
  1218. + #ifdef DEBUG
  1219. +     Dprintf(stderr, "*** cwd=\"%s\"\n", d);
  1220. + #endif
  1221. +     return d;
  1222.   }
  1223.   
  1224. Index: dusort.1
  1225. *** PL0/dusort.1    Tue Aug 24 18:00:14 1993
  1226. --- dusort.1    Tue Aug 24 18:00:35 1993
  1227. ***************
  1228. *** 1,4 ****
  1229. ! .\" @(#) dusort.1 1.5 93/08/18 00:09:04
  1230.   .TH DUSORT 1
  1231.   .SH NAME
  1232.   dusort \- Sort disk usage summaries.
  1233. --- 1,4 ----
  1234. ! .\" @(#) dusort.1 1.6 93/08/24 18:00:31
  1235.   .TH DUSORT 1
  1236.   .SH NAME
  1237.   dusort \- Sort disk usage summaries.
  1238. ***************
  1239. *** 5,10 ****
  1240. --- 5,13 ----
  1241.   .SH SYNTAX
  1242.   .B dusort
  1243.   [
  1244. + .B \-f
  1245. + delim
  1246. + ] [
  1247.   .B \-t
  1248.   threshold ] [ file ]
  1249.   .SH DESCRIPTION
  1250. ***************
  1251. *** 19,30 ****
  1252.   and produces a listing to the standard output.  The listing will show
  1253.   the contents of the directories sorted in descending order, and indented
  1254.   under their parent directory.  The input data lines must have at least
  1255. ! two white-space delimited fields.  The first field is the disk usage
  1256. ! and the last field is the pathname.  The
  1257. ! .B \-t
  1258. ! option suppresses any entries less than
  1259.   .I threshold
  1260. ! disk blocks.
  1261.   .SH SEE ALSO
  1262.   du(1L)
  1263.   .SH BUGS
  1264. --- 22,45 ----
  1265.   and produces a listing to the standard output.  The listing will show
  1266.   the contents of the directories sorted in descending order, and indented
  1267.   under their parent directory.  The input data lines must have at least
  1268. ! two fields:  the disk usage value in the first field of the line and
  1269. ! the pathname in the last field of the line.  There may be additional
  1270. ! fields between these two; they will be ignored.  The tab character is
  1271. ! the default field delimiter.
  1272. ! .P
  1273. ! The following options are available.
  1274. ! .IP "\-f \fIdelim\fP" 12
  1275. ! Changes the field delimiter.  The field delimiter will be a sequence of
  1276. ! one or more of the characters specified by the
  1277. ! .I delim
  1278. ! argument.
  1279. ! .IP "\-t \fIthreshold\fP" 12
  1280. ! Normally,
  1281. ! .I dusort
  1282. ! lists all entries given to it.  This option sets a threshold, and any
  1283. ! input with a disk usage value less than the
  1284.   .I threshold
  1285. ! argument will be discarded.
  1286.   .SH SEE ALSO
  1287.   du(1L)
  1288.   .SH BUGS
  1289. Index: dusort.c
  1290. *** PL0/dusort.c    Tue Aug 24 18:00:15 1993
  1291. --- dusort.c    Fri Aug 27 16:54:37 1993
  1292. ***************
  1293. *** 1,4 ****
  1294. ! /* @(#) dusort.c 1.7 93/08/18 00:09:05
  1295.    *
  1296.    * disk usage sorter
  1297.    *
  1298. --- 1,4 ----
  1299. ! /* @(#) dusort.c 1.9 93/08/27 16:25:24
  1300.    *
  1301.    * disk usage sorter
  1302.    *
  1303. ***************
  1304. *** 19,27 ****
  1305.   #include <ctype.h>
  1306.   #include <string.h>
  1307.   
  1308. ! #define USAGE        "usage: %s [-t threshold] [file]\n"
  1309.   #define INDENT        4
  1310.   #define LISTINCR    16
  1311.   #define TRUE        1
  1312.   #define FALSE        0
  1313.   
  1314. --- 19,28 ----
  1315.   #include <ctype.h>
  1316.   #include <string.h>
  1317.   
  1318. ! #define USAGE        "usage: %s [-t threshold] [-f delim] [file]\n"
  1319.   #define INDENT        4
  1320.   #define LISTINCR    16
  1321. + #define DFLT_DELIM    "\t"
  1322.   #define TRUE        1
  1323.   #define FALSE        0
  1324.   
  1325. ***************
  1326. *** 63,69 ****
  1327.   int argc;
  1328.   char *argv[];
  1329.   {
  1330. !     char buf[1024], *fname, *last_field, *bufp, *s;
  1331.       int lineno, leading_slash, i;
  1332.       long size;
  1333.       struct duentry *du_root, *p, *p1;
  1334. --- 64,70 ----
  1335.   int argc;
  1336.   char *argv[];
  1337.   {
  1338. !     char buf[1024], *field_delim, *fname, *last_field, *s;
  1339.       int lineno, leading_slash, i;
  1340.       long size;
  1341.       struct duentry *du_root, *p, *p1;
  1342. ***************
  1343. *** 74,86 ****
  1344.        * Initialize.
  1345.        */
  1346.       Threshold = 0L;
  1347.       du_root = make_entry("", FALSE);
  1348.   
  1349.       /*
  1350.        * Crack command line.
  1351.        */
  1352. !     while ((i = getopt(argc, argv, "t:")) != EOF) {
  1353.           switch (i) {
  1354.           case 't':
  1355.               if ((Threshold=atol(optarg)) <= 0L && strcmp(optarg, "0") != 0) {
  1356.                   fprintf(stderr, "%s: bad threshold value \"%s\"\n",
  1357. --- 75,91 ----
  1358.        * Initialize.
  1359.        */
  1360.       Threshold = 0L;
  1361. +     field_delim = DFLT_DELIM;
  1362.       du_root = make_entry("", FALSE);
  1363.   
  1364.       /*
  1365.        * Crack command line.
  1366.        */
  1367. !     while ((i = getopt(argc, argv, "f:t:")) != EOF) {
  1368.           switch (i) {
  1369. +         case 'f':
  1370. +             field_delim = optarg;
  1371. +             break;
  1372.           case 't':
  1373.               if ((Threshold=atol(optarg)) <= 0L && strcmp(optarg, "0") != 0) {
  1374.                   fprintf(stderr, "%s: bad threshold value \"%s\"\n",
  1375. ***************
  1376. *** 123,150 ****
  1377.       while (++lineno, fgets(buf, sizeof(buf), stdin) != NULL) {
  1378.   
  1379.           /*
  1380. !          * Break the line up into fields.  Save the first field as the size.
  1381.            */
  1382. !         s = NULL;
  1383. !         bufp = buf;
  1384. !         i = 0;
  1385. !         while (last_field = s, (s = strtok(bufp, " \t\n")) != NULL) {
  1386. !             bufp = NULL;
  1387. !             if (i++ == 0)
  1388. !                 size = atol(s);
  1389. !         }
  1390. !         if (i < 2) {
  1391.               fprintf(stderr, "%s(%d): line ignored\n", fname, lineno);
  1392.               continue;
  1393.           }
  1394.   
  1395.           /*
  1396. !          * Ignore this entry if it is smaller than what we want.
  1397.            */
  1398. !         if (size < Threshold)
  1399.               continue;
  1400.   
  1401.           /*
  1402.            * Break the pathname into components, and descend down
  1403.            * into the tree, creating nodes as required.
  1404.            */
  1405. --- 128,165 ----
  1406.       while (++lineno, fgets(buf, sizeof(buf), stdin) != NULL) {
  1407.   
  1408.           /*
  1409. !          * Locate end of the first field.
  1410.            */
  1411. !         for (s = buf ; *s != '\0' && strchr(field_delim, *s) == NULL ; ++s)
  1412. !             ;
  1413. !         if (*s == '\0') {
  1414.               fprintf(stderr, "%s(%d): line ignored\n", fname, lineno);
  1415.               continue;
  1416.           }
  1417.   
  1418.           /*
  1419. !          * Save the field as the size.  Ignore line if size is below threshold.
  1420.            */
  1421. !         *s = '\0';
  1422. !         if ((size = atol(buf)) < Threshold)
  1423.               continue;
  1424.   
  1425.           /*
  1426. +          * Move to the end of the line and trim the trailing newline.
  1427. +          */
  1428. +         ++s;
  1429. +         s += strlen(s)-1;
  1430. +         if (*s == '\n')
  1431. +             *s-- = '\0';
  1432. +         /*
  1433. +          * Locate the start of the last field.
  1434. +          */
  1435. +         while (*s != '\0' && strchr(field_delim, *s) == NULL)
  1436. +             --s;
  1437. +         last_field = s+1;
  1438. +         /*
  1439.            * Break the pathname into components, and descend down
  1440.            * into the tree, creating nodes as required.
  1441.            */
  1442. ***************
  1443. *** 314,320 ****
  1444.   }
  1445.   
  1446.   
  1447. ! static char malloc_error[] = "error - out of memory [malloc failed]\n";
  1448.   
  1449.   char *xstrdup(s)
  1450.   register char *s;
  1451. --- 329,335 ----
  1452.   }
  1453.   
  1454.   
  1455. ! static char malloc_errmssg[] = "error - out of memory [malloc failed]\n";
  1456.   
  1457.   char *xstrdup(s)
  1458.   register char *s;
  1459. ***************
  1460. *** 321,327 ****
  1461.   {
  1462.       register char *s1;
  1463.       if ((s1 = (char *) malloc((unsigned)strlen(s)+1)) == NULL) {
  1464. !         fputs(malloc_error, stderr);
  1465.           exit(1);
  1466.       }
  1467.       return strcpy(s1, s);
  1468. --- 336,342 ----
  1469.   {
  1470.       register char *s1;
  1471.       if ((s1 = (char *) malloc((unsigned)strlen(s)+1)) == NULL) {
  1472. !         fputs(malloc_errmssg, stderr);
  1473.           exit(1);
  1474.       }
  1475.       return strcpy(s1, s);
  1476. ***************
  1477. *** 332,338 ****
  1478.   {
  1479.       register PTRTYPE *s;
  1480.       if ((s = malloc(n)) == NULL) {
  1481. !         fputs(malloc_error, stderr);
  1482.           exit(1);
  1483.       }
  1484.       return s;
  1485. --- 347,353 ----
  1486.   {
  1487.       register PTRTYPE *s;
  1488.       if ((s = malloc(n)) == NULL) {
  1489. !         fputs(malloc_errmssg, stderr);
  1490.           exit(1);
  1491.       }
  1492.       return s;
  1493. ***************
  1494. *** 343,349 ****
  1495.   register unsigned n;
  1496.   {
  1497.       if ((s = (s == NULL ? malloc(n) : realloc(s, n))) == NULL) {
  1498. !         fputs(malloc_error, stderr);
  1499.           exit(1);
  1500.       }
  1501.       return s;
  1502. --- 358,364 ----
  1503.   register unsigned n;
  1504.   {
  1505.       if ((s = (s == NULL ? malloc(n) : realloc(s, n))) == NULL) {
  1506. !         fputs(malloc_errmssg, stderr);
  1507.           exit(1);
  1508.       }
  1509.       return s;
  1510. Index: fsinfo.c
  1511. *** PL0/fsinfo.c    Tue Aug 24 18:00:11 1993
  1512. --- fsinfo.c    Thu Aug 26 05:22:46 1993
  1513. ***************
  1514. *** 1,5 ****
  1515.   #ifndef lint
  1516. ! static char SCCSID[] = "@(#) fsinfo.c 1.25 93/08/18 00:09:06";
  1517.   #endif
  1518.   
  1519.   /*
  1520. --- 1,5 ----
  1521.   #ifndef lint
  1522. ! static char SCCSID[] = "@(#) fsinfo.c 1.27 93/08/26 05:22:39";
  1523.   #endif
  1524.   
  1525.   /*
  1526. ***************
  1527. *** 116,121 ****
  1528. --- 116,134 ----
  1529.   #    include <sys/vfs.h>
  1530.   #    define STATFS(MNT, PTR, PSIZE, FSTYPE) \
  1531.           statfs(MNT, PTR)
  1532. + #endif
  1533. + #ifdef USE_STATFS_ULTRIX
  1534. + #    include <sys/param.h>
  1535. + #    include <sys/mount.h>
  1536. +     struct statfs {
  1537. +         long f_bsize, f_files;
  1538. +     };
  1539. +     static struct fs_data fs_data;
  1540. + #    define STATFS(MNT, PTR, PSIZE, FSTYPE) \
  1541. +         (statfs(MNT, &fs_data) != 1 ? -1 : ( \
  1542. +             (PTR)->f_bsize = fs_data.fd_bsize, \
  1543. +             (PTR)->f_files = fs_data.fd_gfree, \
  1544. +             0))
  1545.   #endif
  1546.   #ifdef USE_STATFS_NONE
  1547.   #    include <sys/param.h>
  1548.